package com.yanqu.road.server.helper;

import com.alibaba.fastjson.JSONObject;
import com.yanqu.road.utils.MD5Security;
import com.yanqu.road.utils.string.StringUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import sun.misc.BASE64Encoder;

import javax.crypto.Cipher;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.io.UnsupportedEncodingException;
import java.nio.charset.StandardCharsets;
import java.security.InvalidKeyException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.*;

public class SignHelper {

	private static Logger logger = LogManager.getLogger(SignHelper.class.getName());

	public static SortedMap<String, String> getParamMap(JSONObject paramObj){
		SortedMap<String, String> paramMap = new TreeMap<>();
		for(Map.Entry<String, Object> dataEntry : paramObj.entrySet()){
			String key = dataEntry.getKey();
			Object value = dataEntry.getValue();
			if(null != value){
				paramMap.put(key, dataEntry.getValue().toString());
			}
		}
		return paramMap;
	}

	/**
	 * 排序参数，构造签名原串，生成小写MD5值
	 *
	 * @param paramMap  签名构造参数
	 * @param appSecret 签名密钥
	 * @return String
	 */
	public static String getSign1(SortedMap<String, String> paramMap, String appSecret) {
		String sign = "";
		if (StringUtils.isNullOrEmpty(appSecret)) {
			return sign;
		}
		StringBuffer sb = new StringBuffer();
		for (Map.Entry<String, String> dataEntry : paramMap.entrySet()) {
			String key = dataEntry.getKey();
			String value = dataEntry.getValue();
			if (!"sign".equals(key)) {
				sb.append(key).append("=").append(value).append("&");
			}
		}
		if (sb.length() > 0) {
			sb.deleteCharAt(sb.length() - 1);
		}
		sb.append("&").append(appSecret);
		try {
//			logger.info("sign pre value:{}", sb.toString());
			sign = MD5Security.md5(sb.toString()).toLowerCase();
//			logger.info("sign value:{}", sign);
		} catch (Exception e) {
			logger.error("getSign error:", e);
		}
		return sign;
	}

	public static String getSign(SortedMap<String, String> paramMap, String appSecret){
		String sign = "";
		if(StringUtils.isNullOrEmpty(appSecret)){
			return sign;
		}
		StringBuffer sb = new StringBuffer();
		for(Map.Entry<String, String> dataEntry : paramMap.entrySet()){
			String key = dataEntry.getKey();
			String value = dataEntry.getValue();
			if(!StringUtils.isNullOrEmpty(value) && !"sign".equals(key)){
				sb.append(key + "=" + value + "&");
			}
		}
		if(sb.length() > 0){
			sb.deleteCharAt(sb.length() - 1);
		}
		sb.append(appSecret);
		try {
//			logger.info("sign pre value:{}", sb.toString());
			sign = MD5Security.md5(sb.toString()).toLowerCase();
//			logger.info("sign value:{}", sign);
		} catch (Exception e) {
			logger.error("getSign error:", e);
		}
		return sign;
	}
	public static String getChatReportSign(SortedMap<String, String> paramMap, String appSecret){
		String sign = "";
		if(StringUtils.isNullOrEmpty(appSecret)){
			return sign;
		}
		StringBuffer sb = new StringBuffer();
		sb.append(appSecret);
		sb.append(paramMap.get("userID"));
		sb.append(paramMap.get("serverID"));
		sb.append(paramMap.get("time"));
		sb.append(paramMap.get("type"));
		try {
			logger.info("chat report sign pre value:{}", sb.toString());
			sign = MD5Security.md5(sb.toString()).toLowerCase();
			logger.info("chat report sign value:{}", sign);
		} catch (Exception e) {
			logger.error("chat report getSign error:", e);
		}
		return sign;
	}

	public static boolean checkSign(SortedMap<String, String> paramMap, String appSecret, String sign){
		if(StringUtils.isNullOrEmpty(sign)){
			return false;
		}
		String encodeSign = getSign(paramMap, appSecret);
		return encodeSign.equals(sign.toLowerCase());
	}

	public static boolean checkSign(String sign, String content) {
		logger.info("sign pre value:{}", content);
		String mySign = "";
		try {
		mySign = MD5Security.md5(content).toLowerCase();
		} catch (Exception e) {
			logger.error("getSign error:", e);
		}
		logger.info("sign value:{}", mySign);
		return Objects.equals(sign, mySign);
	}

	public static void main(String[] args) throws Exception {
//		try {
//			SortedMap<String, String> paramMap = new TreeMap<>();
//			paramMap.put("uname", "abc");
//			paramMap.put("time", "1584597125");
//			String sign = SignManager.getSign(paramMap, SignManager.APP_SECRET);
//			System.out.println(sign);
//		} catch (NoSuchAlgorithmException | UnsupportedEncodingException e) {
//			logger.error("异常错误",e);
//		}
		SortedMap<String, String> paramMap = new TreeMap<>();
		paramMap.put("userID", "svip01");
		paramMap.put("serverID", "99900002");
		paramMap.put("roleID", "999000020000417");
		paramMap.put("orderID", "1000000");
		paramMap.put("giftID", "101000");
		paramMap.put("giftNum", "10");
		String sign = SignHelper.getSign(paramMap, "484c502802472f05fcea6f5d01641e21");
		System.out.println(sign);
	}

	public static String EncoderByMd5(String str) throws NoSuchAlgorithmException, UnsupportedEncodingException {
		MessageDigest md5 = MessageDigest.getInstance("MD5");
		BASE64Encoder base64en = new BASE64Encoder();
		String newstr = base64en.encode(md5.digest(str.getBytes("utf-8")));
		return newstr;
	}

	/**
	 * 检查websocketSign
	 * @param sign 客户端sign
	 * @param userId 用户id
	 * @param openId 账户唯一id
	 * @param v 下发给客户端的value值
	 * @return
	 */
	public static boolean checkWebsocketSign(String sign, long userId, String openId, String v) {
		String src = "";
		try {
			List<String> strs = StringUtils.stringToStringList(v, "_");
			String key = strs.get(0);
			String n = strs.get(1);

			int index = Integer.valueOf(n) % 5;

			int sum = 0;
			for (int i = 0; i < key.length(); i++) {
				int charInt = Integer.valueOf(key.charAt(i));

				if (charInt % 2 == 0) {
					sum += (charInt << index);
				} else {
					sum += (charInt >> index);
				}

			}

			if (sum % 5 == 0) {
				src = key + userId + openId + sum + n;
			} else if (sum % 5 == 1) {
				src = userId + key + openId + sum + n;
			} else if (sum % 5 == 2) {
				src = userId + openId + key + sum + n;
			} else if (sum % 5 == 3) {
				src = userId + openId + sum + key +  n;
			} else {
				src = userId + openId + sum + n + key;
			}
			String mySign = MD5Security.md5(src).toLowerCase();

			if (sign.equals(mySign)) {
				logger.debug("login sign success : {} {} {} {} {}, mySign : {}", sign, userId, openId, v, src, mySign);
				return true;
			}
			logger.debug("login sign failed : {} {} {} {} {}, mySign : {}", sign, userId, openId, v, src, mySign);
			return false;
		} catch (Exception ex) {
			logger.error("login sign error : {} {} {} {} {} \n {}", sign, userId, openId, v, src, ex);
			return true;
		}

	}

	/**
	 * AES ECB加密
	 *
	 * @text 需要加密的内容
	 * @key 加密密码
	 */
	public static String encryptByAES(String text, String key) throws Exception {
		// 创建密码器
		Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
		byte[] byteContent = text.getBytes("utf-8");
		// 初始化
		cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(key.getBytes("utf-8"), "AES"));
		byte[] result = cipher.doFinal(byteContent);
		// 加密
		return Base64.getEncoder().encodeToString(result);
	}

	/**
	 * AES ECB解密
	 * @text 待解密内容
	 * @key 解密密钥
	 */
	public static String decryptByAES(String text, String key) throws Exception {
		// 创建密码器
		Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5Padding");
		// 初始化
		cipher.init(Cipher.DECRYPT_MODE, new SecretKeySpec(key.getBytes("utf-8"), "AES"));
		byte[] result = cipher.doFinal(Base64.getDecoder().decode(text));
		// 解密
		return new String(result, "utf-8");
	}

	public static String hmacSha256(SortedMap<String, String> paramMap, String appSecret) throws NoSuchAlgorithmException, InvalidKeyException {
		String sign = "";
		if(StringUtils.isNullOrEmpty(appSecret)){
			return sign;
		}
		StringBuffer sb = new StringBuffer();
		for(Map.Entry<String, String> dataEntry : paramMap.entrySet()){
			String key = dataEntry.getKey();
			String value = dataEntry.getValue();
			if(!StringUtils.isNullOrEmpty(value) && !"sign".equals(key)){
				sb.append(key + "=" + value + "&");
			}
		}
		if(sb.length() > 0){
			sb.deleteCharAt(sb.length() - 1);
		}
		String data = sb.toString();

		Mac sha256Hmac = Mac.getInstance("HmacSHA256");
		SecretKeySpec secretKeySpec = new SecretKeySpec(appSecret.getBytes(StandardCharsets.UTF_8), "HmacSHA256");
		sha256Hmac.init(secretKeySpec);

		byte[] signedBytes = sha256Hmac.doFinal(data.getBytes(StandardCharsets.UTF_8));
		sign = Base64.getEncoder().encodeToString(signedBytes);
		return sign;
	}

}
